#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>

#include "teex/util.h"
#include "openssl/ec.h"
#include <openssl/ecdsa.h>
#include "openssl/evp.h"
#include <openssl/x509.h>
#include <openssl/cmac.h>
#include <openssl/conf.h>
#include "openssl/err.h"
#include <openssl/pem.h> 
#include <openssl/bn.h> 
#include <openssl/x509v3.h>


int isNumberStr(char* str)
{
	char c = 0, *num_str = "0123456789abcdef";
	if (str == NULL)
		return 0;

	if (strncasecmp(str, "0x", 2) == 0) {
		str += 2;
	}

	while (*str) {
		c = tolower(*str);
		if (strchr(num_str, c) == NULL) {
			return 0;
		}
		str++;
	}

	return 1;
}


char* teexHexStrDup(char *str, int size)
{
	char *retp = NULL;

	if (str == NULL)
		return NULL;

	/* skip the '0x' in string */
	if (strncasecmp(str, "0x", 2) == 0)
		str += 2;

	/* check is number string */
	if (isNumberStr(str) == 0) {
		return NULL;
	}

	if (size > 0 && strlen(str) != size)
		return NULL;

	return strdup(str);

}

int teexGetLine(TEEX_SSL *ts, char *buf, int size)
{
	int i = 0, n;
	char c = 0;

	while (i < (size-1)) {
		if ((n = TEEX_read(ts, &c, 1)) <= 0)
			break;

		if (c == '\n')
			break;
		
		buf[i] = c;
		i++;

	}

	buf[i] = c;

	return i;
}


void teexBinToHexStr(void *vsrc, size_t len, char *out) {
	const char *_hextable = "0123456789abcdef";
	const unsigned char *src= (const unsigned char *) vsrc;
	char *bp = out;
	size_t i;
	for(i= 0; i < len; ++i) {
		*(bp++) = _hextable[(src[i]>>4)&0xf];
		*(bp++) = _hextable[src[i]&0xf];
	} 
	*bp = '\0';
}

char *sha256AndToHexStr(char *msg, size_t mlen)
{
	unsigned char hash_hex[32];
	char *hash_str = (char*)malloc(65);

	//EVP_MD_CTX *ctx = EVP_MD_CTX_new();
	memset(hash_hex, 0, 32);


	SHA256((unsigned char *)msg, mlen, hash_hex);
	
	/* transfer hash_hex into str */
	memset(hash_str, 0, 65);
	teexBinToHexStr(hash_hex, 32, hash_str);

	return hash_str;
}

int teexConnect(char *host, int port)
{
	int r, clientfd;
	struct addrinfo *addrs = NULL, *addr;
	struct addrinfo hints;

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;

	char port_string[20];
	snprintf(port_string, 19, "%d", port);
	r = getaddrinfo(host, port_string, &hints, &addrs);
	if (r != 0)
		return -1;
	
	clientfd = ~0;
	for (addr= addrs; addr != NULL; addr= addr->ai_next) {
		clientfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
		if (clientfd < 0)
			continue;
		struct sockaddr ai_addr = *(addr->ai_addr);
		r = connect(clientfd, &ai_addr, (int) addr->ai_addrlen);
		if (r == 0)
			break;
		close(clientfd);
		clientfd = ~0;
	}
	freeaddrinfo(addrs);
	if(clientfd < 0)
		return -1;

	return clientfd;
}





















